package com.example.tys.baseapplication.util

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import androidx.lifecycle.MutableLiveData

/**
 * 网络状态监听
 * 1.[NetWorkMonitor.start]
 * 2.[NetWorkMonitor.netWorkType] LiveData observeForever
 */
open class NetWorkMonitor private constructor(val mContext: Context) {

    companion object {

        private const val TAG = "NetWorkMonitor"

        private var INSTANCE: NetWorkMonitor? = null

        var netWorkType = MutableLiveData<TRANSPORT>()

        fun start(context: Context) {
            if (INSTANCE != null) {
                return
            }
            INSTANCE = NetWorkMonitor(context.applicationContext)
        }

        fun stop() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                INSTANCE?.unRegisterNetCallBack()
            } else {
                INSTANCE?.unregisterNetBroadcast()
            }
            INSTANCE = null
        }

    }


    private val mConnectionReceiver by lazy {
        object : BroadcastReceiver() {
            @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
            override fun onReceive(context: Context?, intent: Intent?) {
                if (intent == null || intent.action == null) {
                    return
                }
                if (intent.action == ConnectivityManager.CONNECTIVITY_ACTION) {
                    val connectivityManager =
                        mContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
                    val info = connectivityManager.activeNetworkInfo
                    var type = TRANSPORT.NONE
                    if (info != null && info.isConnected) {
                        type = when (info.type) {
                            ConnectivityManager.TYPE_WIFI -> {
                                TRANSPORT.WIFI
                            }
                            ConnectivityManager.TYPE_MOBILE -> {
                                TRANSPORT.CELLULAR
                            }
                            ConnectivityManager.TYPE_ETHERNET -> {
                                TRANSPORT.ETHERNET
                            }
                            else -> {
                                TRANSPORT.NONE
                            }
                        }
                    }
                    Log.d(TAG, "Network broadcast received $type")
                    netWorkChanged(type)
                }
            }
        }
    }

    private val mNetWorkCallback by lazy {
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        object : ConnectivityManager.NetworkCallback() {
            override fun onLost(network: Network) {
                //网络丢失 多次
                super.onLost(network)
                Log.d(TAG, "Network callback received ${TRANSPORT.NONE}")
                netWorkChanged(TRANSPORT.NONE)
            }

            override fun onAvailable(network: Network) {
                super.onAvailable(network)
                val cm =
                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
                val networkCapabilities = cm.getNetworkCapabilities(network)
                val type = networkCapabilities?.let {
                    when {
                        it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
                            TRANSPORT.WIFI
                        }
                        it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
                            TRANSPORT.CELLULAR
                        }
                        it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
                            TRANSPORT.ETHERNET
                        }
                        else -> {
                            TRANSPORT.NONE
                        }
                    }
                }
                type?.let {
                    Log.d(TAG, "Network callback received $type")
                    netWorkChanged(type)
                }
            }
        }
    }

    open fun netWorkChanged(currentNetType: TRANSPORT) {
        //多次触发
        netWorkType.postValue(currentNetType)
    }


    init {
        @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            registerNetCallBack()
        } else {
            registerNetBroadcast()
        }
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
    private fun registerNetCallBack() {
        val cm = mContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        cm.registerNetworkCallback(NetworkRequest.Builder().build(), mNetWorkCallback)
    }


    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun unRegisterNetCallBack() {
        val cm = mContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        cm.unregisterNetworkCallback(mNetWorkCallback)
    }

    private fun registerNetBroadcast() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
        mContext.registerReceiver(mConnectionReceiver, intentFilter)
    }

    private fun unregisterNetBroadcast() {
        mContext.unregisterReceiver(mConnectionReceiver)
    }


}

enum class TRANSPORT {
    NONE, WIFI, CELLULAR, ETHERNET;

    fun isAvailable(): Boolean {
        return compareTo(NONE) > 0
    }
}